#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "functions.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função calcula e retorna o tamanho da região de dados desejada.                                                                     // 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int tamanho(FILE *fl)
{
	int i,tam[4];
	for(i=0;i<4;i++) tam[i]=getc(fl); // armazena os 4 bytes relativos ao tamanho da região desejada.
	return tam[3]+tam[2]*pow(2,7)+tam[1]*pow(2,14)+tam[0]*pow(2,21); // elimina os primeiros bits de cada byte e retorna o valor do tamanho.
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função armazena o nome das tags e calcula o seu tamanho.                                                                            //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
char *info(FILE *fl, int *tam)
{
	char *tag=malloc(5*sizeof(char));	
	char *flag=malloc(2*sizeof(char)),j;
	int i;
	for(i=0;i<4;i++) tag[i]=getc(fl); // armazena o nome da tag.
	tag[4]=10; // adiciona um '\n' na string que guarda o nome da tag.
	*tam=tamanho(fl); // calcula o tamanho da tag.
	for(i=0;i<2;i++) flag[i]=getc(fl); // armazena os flags da tag.
	j=getc(fl); // byte descartável, pois é sempre nulo.
	free(flag);
	return tag;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função mostra na tela algumas das características do arquivo de áudio.                                                              //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int dados_musica(FILE *fl)
{
	
	printf("Indentificador de Arquivo: ");
	for(int i=0;i<3;i++) printf("%c",getc(fl));
	puts("");
	for(int i=0;i<2;i++)
	{
		if(i==0) printf("Major Version: %d\n",getc(fl));
		if(i==1) printf("Revisison Number: %d\n",getc(fl));
	}
	unsigned char var=getc(fl);
	if(var&128==128) printf("Unsynchronisation  [YES]\n");
	else printf("Unsynchronisation  [NO]\n");
	if(var&64==64) printf("Extended Header    [YES]\n");
	else printf("Extended Header    [NO]\n");
	if(var&32==32) printf("Experimental Stage [YES]\n");
	else printf("Experimental Stage [NO]\n");
	int w=tamanho(fl);
	printf("O tamanho do header é de: %d Bytes\n",w);
	return w;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função testa se os dados são referentes a uma tag. Se sim, os dados são mostrados na tela.                                          //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void tag_info(FILE *fl, int tags_len)
{
	FILE *ff;
	int tam,i,verdade=0,resto=0;
	unsigned char *tags,*conteudo,*str=malloc(5*sizeof(char));
	while(resto<tags_len)
	{
		tags=info(fl, &tam); //armazena o suposto noe da tag.
		ff=fopen("frames.txt","r"); // abre um arquivo com todos os possíveis nomes de tags.
		while(!feof(ff) && verdade==0)         // aqui é comparado o nome que foi pego no arquivo de áudio com os nomes no arquivo que foi
		{                                      // aberto anteriormente, se em algum momento não houver nenhuma correspondência é pq não há
			for(i=0;i<5;i++) str[i]=getc(ff);  // mais nenhuma tag.
			if(strcmp(tags,str)==0) verdade=1;
			else verdade=0;
		}
		fclose(ff);
		if(verdade==1) // aqui é onde os dados da tag são mostrados na tela.
		{
			conteudo=malloc((tam-1)*sizeof(char));
			for(i=0;i<tam-1;i++) conteudo[i]=getc(fl);
			printf("%s\n",conteudo);
			free(tags);
			resto=resto+10+tam;
			verdade=0;
		}
		else resto=tags_len;
	}	
	free(conteudo);		
	free(str);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função calcula o bit rate do frame de acordo com os bits, do header do frame, referentes ao bit rate.                               //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int bt_rt(int bit_rate)
{
	if (bit_rate==0) bit_rate=0;	
	else if ((bit_rate>0)&&(bit_rate<=5))
	bit_rate=(32+(bit_rate-1)*8)*1000;
	else if ((bit_rate>5)&&(bit_rate<10))
	bit_rate=(80+(bit_rate-6)*16)*1000;
	else if ((bit_rate>=10)&&(bit_rate<=13))
	bit_rate=(160+(bit_rate-10)*32)*1000;
	else bit_rate=320000;
	return bit_rate;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Este função calcula o sample rate do frame.                                                                                              //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int sp_rt(int sample)
{
	if(sample==0) sample=44100;
	else if(sample==1) sample=48000;
	else sample=32000;
	return sample;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função inicializa uma estrutura para que se possa armazenar todas as caracteríticas do frame em questão.                            //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
header *inicia_header()
{
	header *hdr=malloc(sizeof(header));
	hdr->head=0;
	hdr->sync=0;
	hdr->bit_rate=0;
	hdr->sample=0;
	hdr->version=0;
	hdr->layer=0;
	hdr->crc=0;
	hdr->padding=0;
	hdr->channel=0;
	hdr->emphasis=0;
	hdr->frame_len=0;
	return hdr;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Esta função armazena as características fundamentais do header, que indicam se realmente é um header.                                    // 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
header header_prt1(header *hdr, FILE *fl)
{
	hdr->head=malloc(4*sizeof(int));
	for(int i=0;i<4;i++) hdr->head[i]=getc(fl);
	hdr->sync=(hdr->head[0]<<3)+((hdr->head[1]&224)>>5);
	hdr->bit_rate=(hdr->head[2]&240)>>4;
	hdr->sample=(hdr->head[2]&12)>>2;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Se for confirmado que é um header esta função é chamada para armazenar as características restantes do header.	                       //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
header header_prt2(header *hdr)
{
	hdr->version=(hdr->head[1]&24)>>3;
	hdr->layer=(hdr->head[1]&6)/2;
	hdr->crc=hdr->head[1]&1;
	hdr->padding=(hdr->head[2]&2)/2;
	hdr->channel=(hdr->head[3]&192)>>6;
	hdr->emphasis=hdr->head[3]&3;
	hdr->sample=sp_rt(hdr->sample);
	hdr->bit_rate=bt_rt(hdr->bit_rate);
	hdr->frame_len=(144*hdr->bit_rate/hdr->sample)+hdr->padding;
}
